/*
 * Msg.cpp
 *
 *  Created on: 2013. 7. 22.
 *      Author: jjaehuny
 */

#include <Dispatcher/Static.h>
#include <Database/Static.h>
#include "ChannelServer.h"
#include "Friends.h"
#include "User.h"

#include "MemCached.h"
#include "MemResultSet.h"

#include <map>
#include <vector>
#include <memory>

#include "Static.h"
#include "Ack.h"

namespace FriendsServer {

void
Msg::OnSocialMyInfo(Dispatcher::Session* pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	SocialMyInfoSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	SocialMyInfoAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "OnSocialMyInfo not found user userkey : ", syn.seq );

		clsuser = Static::Instance().SetUser(syn.seq);
		clsuser->Initialize(pchannelserver->GetChannelKey());

		clsuser->SetSocialId(syn.socialid);
		clsuser->SetUserSeq(syn.seq);

		clsuser->GetUserInfo().nickName		= syn.nickname;
		clsuser->GetUserInfo().profileUrl	= syn.profile_url;

		int ret = Memcache->GetInfoSocialMine(clsuser);
		if (ACK_OK != ret)
		{
			SendFailAck(pchannelserver, ack, ret);
			return;
		}

		clsuser->SetGameUserSeq();
		clsuser->SetNoAppFriends();
	}
	else
	{
		clsuser->GetUserInfo().nickName		= syn.nickname;
		clsuser->GetUserInfo().profileUrl	= syn.profile_url;

		LOG(DEV, "nickname=", syn.nickname, " url=", syn.profile_url);

		Memcache->SetMyInfo(clsuser);
	}

	ack.result			= ACK_OK;
	ack.heart_count		= clsuser->GetHeartCount();
	ack.heart_blocked	= clsuser->GetUserInfo().isHeartBlock;
	ack.profile_opened	= clsuser->GetUserInfo().isProfileBlock;
	ack.invite_block	= clsuser->GetUserInfo().isInviteBlock;
	ack.gender			= clsuser->GetUserInfo().gender;
	ack.gender_open		= clsuser->GetUserInfo().isGenderOpen;
	ack.birthday		= clsuser->GetUserInfo().birthday;
	ack.birth_open		= clsuser->GetUserInfo().isBirthdayOpen;

	pchannelserver->SendMsg(ack);
	clsuser->KillTimer();
}

void
Msg::OnReceiveSocialIDSendToUserSeq(Dispatcher::Session* pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	SocialUserSeqSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	LOG(DEV, "count : ", static_cast<uint32_t>(syn.array_social_id.size()) );

	SocialUserSeqAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	auto & socialFriendsTree = clsuser->GetSocialFriendsTree();
	auto & friendsTree = clsuser->GetFriendsTree();
	auto synitr = syn.array_social_id.begin();
	for( ; synitr != syn.array_social_id.end() ; ++synitr )
	{
		uint32_t frUserSeq = 0;
		auto socialitr = socialFriendsTree.find(*synitr);
		if (socialFriendsTree.end() == socialitr)
		{
			int ret = clsuser->AddFriendAndInsertDB_Kakao(*synitr, &frUserSeq);
			if (ACK_OK != ret)
			{
				SendFailAck(pchannelserver, ack, ret);
				return;
			}
		}
		else
			frUserSeq = socialitr->second;

		iSocialUserSeqInfo iSocialUserSeq;

		iSocialUserSeq.socialid = *synitr;
		iSocialUserSeq.userseq = frUserSeq;
		User::FRIENDSTREE::iterator fritr = friendsTree.find(frUserSeq);

		if (friendsTree.end() == fritr)
		{
			iSocialUserSeq.is_delete = 1;
		}

		ack.array_social_userseq_info.push_back(iSocialUserSeq);
	}

	ack.result = ACK_OK;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnInGameFriendsUserSeq(Dispatcher::Session* pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	GameUserSeqSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);

	GameUserSeqAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	User::FRIENDSTREE & friendsTree = clsuser->GetFriendsTree();

	User::FRIENDSTREE::iterator fritr = friendsTree.begin();
	for( ; fritr != friendsTree.end() ; ++fritr )
	{
		if ( 2 == fritr->second.friendType && 0 == fritr->second.friendDelTime )
		{
			iGameUserSeqInfo iGameUserSeq;
			iGameUserSeq.socialid = fritr->second.socialID;
			iGameUserSeq.userseq = fritr->first;
			ack.array_game_userseq_info.push_back(iGameUserSeq);
		}
	}

	ack.result = ACK_OK;
	pchannelserver->SendMsg(ack);
}

void
Msg::OnMainListSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	MainListSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	MainListAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	ack.heart_count = clsuser->GetHeartCount();

	int16_t eRes = clsuser->GetMyRanking();

	ack.my_ranking				= clsuser->GetMyRank();
	ack.last_week_friend_count	= clsuser->GetFriendRankCount();

	ack.result = eRes; //ACK_OK;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnFriendsDetailInfoFromKakao(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	SocialFriendsSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	LOG(DEV, "count : ", static_cast<uint32_t>(syn.userseq.size()) );

	SocialFriendsAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	User::FRIENDSTREE & friendsTree = clsuser->GetFriendsTree();
	auto synitr = syn.userseq.begin();
	for( ; synitr != syn.userseq.end() ; ++synitr )
	{
		uint32_t friendSeq = *synitr;
		User::FRIENDSTREE::iterator socialitr = friendsTree.find(friendSeq);
		if (friendsTree.end() == socialitr)
		{
			SendFailAck(pchannelserver, ack, ACK_NO_DATA);
			return;
		}

		User::UserInfo userinfo;
		int ret = Memcache->GetInfoSocialOther(clsuser, friendSeq, userinfo);
		if (ACK_OK != ret)
		{
			SendFailAck(pchannelserver, ack, ret);
			return;
		}

		time_t curTime;
		curTime = time(NULL);

		iSocialFriendInfo iFriend;
		iFriend.userseq = friendSeq;

		iFriend.no_play_period = 0;
		if (curTime - userinfo.lastLoginTime != 0)
			iFriend.no_play_period = (curTime - userinfo.lastLoginTime) / ONE_DAY;

		iFriend.is_connect_requested = 1;
		if ( socialitr->second.connectReqTime < curTime )
			iFriend.is_connect_requested = 0;

		iFriend.is_heart_sent = 1;
		if ( socialitr->second.heartTime < curTime )
			iFriend.is_heart_sent = 0;

		ack.array_Friends.push_back(iFriend);
	}

	ack.result = ACK_OK;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnFriendsDetailInfoFromInGame(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	GameFriendsSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	LOG(DEV, "page : ", static_cast<uint32_t>(syn.userseq.size()) );

	GameFriendsAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	User::FRIENDSTREE & friendsTree = clsuser->GetFriendsTree();

	auto synitr = syn.userseq.begin();
	for( ; synitr != syn.userseq.end() ; ++synitr )
	{
		uint32_t friendSeq = *synitr;
		User::FRIENDSTREE::iterator fritr = friendsTree.find(friendSeq);
		if (friendsTree.end() == fritr)
		{
			LOG(DEV, "not found user");
			return;
		}

		User::UserInfo userinfo;
		int ret = Memcache->GetInfoSocialOther(clsuser, friendSeq, userinfo);
		if (ACK_OK != ret)
		{
			SendFailAck(pchannelserver, ack, ret);
			return;
		}

		iGameFriendInfo iFriend;

		iFriend.userseq = friendSeq;

		time_t curTime;
		curTime = time(NULL);

		iFriend.nickname = userinfo.nickName;
		iFriend.profile_url = userinfo.profileUrl;

		iFriend.no_play_period = 0;
		if (curTime - userinfo.lastLoginTime != 0)
			iFriend.no_play_period = (curTime - userinfo.lastLoginTime) / ONE_DAY;

		iFriend.is_connect_requested = 1;
		if ( fritr->second.connectReqTime < curTime )
			iFriend.is_connect_requested = 0;

		iFriend.is_heart_sent = 1;
		if ( fritr->second.heartTime < curTime )
			iFriend.is_heart_sent = 0;

		ack.array_Friends.push_back(iFriend);
	}

	ack.result = ACK_OK;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnInviteNoAppSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	InviteNoAppSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	LOG(DEV, "user_id : ", syn.user_id );

	InviteNoAppAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	int ret = clsuser->AddInviteNoAppFriend(syn.user_id);
	if (ACK_OK != ret)
	{
		SendFailAck(pchannelserver, ack, ret);
		return;
	}

	clsuser->AddInviteCount(1);

	// web 에서 초대 인원 수 확인 후 보상 할 수 있도록 flush 함.
	clsuser->FlushUserInfo();

	ack.heart_count = clsuser->AddHeartCount(syn.heart_count_max, syn.send_heart_count);
	ack.invite_count = clsuser->GetInviteCount();
	ack.result = ACK_OK;
	pchannelserver->SendMsg(ack);
}

void
Msg::OnNewsCountSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	NewsCountSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);

	NewsCountAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_select_data_news_count(", syn.seq, ")");
	if (0 != res.GetSQLError())
	{
		SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
		return;
	}

	if (res.end() == res.begin())
	{
		SendFailAck(pchannelserver, ack, ACK_NO_DATA);
		return;
	}

	for(Database::ResultSet::iterator itr = res.begin(); itr != res.end(); itr++)
	{
		clsuser->SetNewsCount( itr->getInt("totalCount") );
	}

	ack.news_count = clsuser->GetNewsCount();
	pchannelserver->SendMsg(ack);
}

void
Msg::OnNewsInfoSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	NewsInfoSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	LOG(DEV, "page : ", static_cast<uint32_t>(syn.page_num) );

	NewsInfoAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_select_data_news(", syn.seq, ",", syn.page_num, ")");
	if (0 != res.GetSQLError())
	{
		LOG(DEV, "sp_news errno : ", errno );
		SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
		return;
	}

	if (res.end() == res.begin())
	{
		LOG(DEV, "sp_news not found" );
		ack.isLastPage = 1;
		SendFailAck(pchannelserver, ack, ACK_OK);
		return;
	}

	int i = 0;
	for(Database::ResultSet::iterator newsitr = res.begin(); newsitr != res.end(); newsitr++, i++)
	{
		iNewsInfo newsinfo;
		newsinfo.news_seq = newsitr->getInt("seq");
		newsinfo.user_seq = newsitr->getInt("fr_userseq");
		newsinfo.news_type = newsitr->getInt("type");
		newsinfo.heart_count = newsitr->getInt("heart_cnt");
		newsinfo.nickname = newsitr->getString("nickname").c_str();
		newsinfo.profile_url = newsitr->getString("profile_url").c_str();
		ack.array_News.push_back(newsinfo);
	}

	int totalCount = clsuser->GetNewsCount();
	int total_page = 0;
	if ( clsuser->GetNewsCount() % 12 == 0 )
		total_page = totalCount / 12;
	else
		total_page = ( totalCount / 12 ) + 1;

	ack.isLastPage = ( syn.page_num == total_page ) ? 1 : 0;

	ack.result = ACK_OK;
	pchannelserver->SendMsg(ack);
}

void
Msg::OnSimpleFriendsSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	SimpleFriendsSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	LOG(DEV, "count : ", static_cast<uint32_t>(syn.user_seq.size()) );

	SimpleFriendsAck ack;
	ack.seq = syn.seq;
	ack.is_medal = syn.is_medal;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	time_t curTime = time(NULL);

	User::FRIENDSTREE & friendsTree = clsuser->GetFriendsTree();

	User::UserInfo userinfo;
	auto synitr = syn.user_seq.begin();
	for(; synitr != syn.user_seq.end(); ++synitr)
	{
		uint32_t friendSeq = *synitr;
		userinfo.Initialize();

		iRealTimeFriendInfo realTimeFrInfo;
		realTimeFrInfo.userseq = friendSeq;

		if (syn.seq != friendSeq)
		{
			User::FRIENDSTREE::iterator fritr = friendsTree.find(friendSeq);
			if (friendsTree.end() == fritr)
			{
				// 클라이언트에서 요청한 유저 중에 탈퇴 유저가 있을 수 있기 때문에 return 주석 처리
//				LOG(DEV, "not found user frtree=", friendSeq);
//				SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
//				return;
				realTimeFrInfo.buff_state = 0;
			}
			else
			{
				if ( fritr->second.buffTime < curTime )
					realTimeFrInfo.buff_state = 1;
				else
					realTimeFrInfo.buff_state = 0;
			}

			int ret = Memcache->GetInfoSocialOther(clsuser, friendSeq, userinfo);
			if (ACK_OK != ret)
			{
				SendFailAck(pchannelserver, ack, ret);
				return;
			}

			realTimeFrInfo.heart_blocked = userinfo.isHeartBlock;
			realTimeFrInfo.invite_blocked = userinfo.isInviteBlock;
			realTimeFrInfo.profile_opend = userinfo.isProfileBlock;
			realTimeFrInfo.gender = userinfo.gender;
			realTimeFrInfo.gender_open = userinfo.isGenderOpen;
			realTimeFrInfo.birthday = userinfo.birthday;
			realTimeFrInfo.birth_open = userinfo.isBirthdayOpen;

			MemCachedData::ServerLocation svrLoc;
			realTimeFrInfo.is_connected = Memcache->GetLocation(friendSeq, svrLoc);
			realTimeFrInfo.server_id = svrLoc.server_id;
			realTimeFrInfo.channel_id = svrLoc.channel_id;
		}

		MemCachedData::Score score;
		Memcache->GetScore(friendSeq, score);

		time_t initTime = clsuser->GetWeekInitTime();

		if (score.reg_date <= initTime)
			realTimeFrInfo.score = 0;
		else
		{
			clsuser->GetThisWeekFriendTree()[friendSeq] = score.curweek;
			realTimeFrInfo.score = score.curweek;
		}

		LOG(DEV, "fr_userseq = ", friendSeq, " score.curweek = ", score.curweek);

		if (1 == syn.is_medal)
		{
			MemCachedData::Medal medal;
			Memcache->GetMedal(friendSeq, medal);

			realTimeFrInfo.gold = medal.gold;
			realTimeFrInfo.silver = medal.silver;
			realTimeFrInfo.bronze = medal.bronze;
		}

		ack.array_Friends.push_back(realTimeFrInfo);
	}

	ack.result = ACK_OK;

	LOG(DEV, "my_userseq = ", clsuser->GetUserSeq(), " weekFriendCount = ", clsuser->GetThisWeekFriendTree().size());
	pchannelserver->SendMsg(ack);
}

void
Msg::OnUpdateProfileSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	UpdateProfileSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	UpdateProfileAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	User::UserInfo & userinfo = clsuser->GetUserInfo();

	userinfo.gender = syn.gender;
	userinfo.isGenderOpen = syn.is_gender_open;
	userinfo.birthday.assign(syn.birthday);
	userinfo.isBirthdayOpen = syn.is_birthday_open;
	userinfo.isProfileBlock = syn.is_profile_open;

	Memcache->SetMyInfo(clsuser);

	ack.result = ACK_OK;
	ack.birthday = syn.birthday;
	ack.gender = syn.gender;
	ack.is_birthday_open = syn.is_birthday_open;
	ack.is_gender_open = syn.is_gender_open;
	ack.is_profile_open = syn.is_profile_open;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnUpdateStatusSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	UpdateStatusSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	UpdateStatusAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	User::UserInfo & userinfo = clsuser->GetUserInfo();

	userinfo.isHeartBlock = syn.is_heart_block;
	userinfo.isInviteBlock = syn.is_invite_block;

	Memcache->SetMyInfo(clsuser);

	ack.result = ACK_OK;
	ack.is_heart_block = syn.is_heart_block;
	ack.is_invite_block = syn.is_invite_block;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnInviteBlockSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	InviteBlockSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	InviteBlockAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;
	ack.invite_block = syn.invite_block;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	auto & userinfo = clsuser->GetUserInfo();

	userinfo.isInviteBlock = syn.invite_block;

	Memcache->SetMyInfo(clsuser);

	pchannelserver->SendMsg(ack);
}

void
Msg::OnFriendShipBlockSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	FriendShipBlockSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	FriendShipBlockAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;
	ack.heart_block = syn.heart_block;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	auto & userinfo = clsuser->GetUserInfo();

	userinfo.isHeartBlock = syn.heart_block;

	Memcache->SetMyInfo(clsuser);

	pchannelserver->SendMsg(ack);
}

void
Msg::OnSendHeartSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	SendHeartSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	SendHeartAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	User::FRIENDSTREE & friendstree = clsuser->GetFriendsTree();

	User::FRIENDSTREE::iterator fritr = friendstree.find(syn.gid);
	if (friendstree.end() == fritr)
	{
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	time_t curtime = time(NULL);
	if (fritr->second.heartTime > curtime)
	{
		SendFailAck(pchannelserver, ack, ACK_UNKNOWN_ERROR);
		return;
	}

	fritr->second.heartTime = curtime + ONE_DAY;

	Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_info_friends_heart_date(", syn.seq, ",", syn.gid, ",", curtime + ONE_DAY, ")");
	if (0 != res.GetSQLError())
	{
		SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
		return;
	}

	int ret = clsuser->SendNewsToFriend(syn.gid, static_cast<int>(recv_friendship_point), syn.recv_heart_count);
	if (ret != ACK_OK)
	{
		SendFailAck(pchannelserver, ack, ret);
		return;
	}

	ack.heart_count = clsuser->AddHeartCount(syn.heart_count_max, syn.send_heart_count);

	pchannelserver->SendMsg(ack);
}

void
Msg::OnRecommendSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	RecommendSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	RecommendAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	if (false == clsuser->GetIsAllow())
	{
		SendFailAck(pchannelserver, ack, ACK_MAX_FRIENDS);
		return;
	}

	auto & frtree = clsuser->GetFriendsTree();
	auto iter = frtree.find(syn.gid);
	if (frtree.end() == iter)
		ack.gid = syn.gid;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnBoastSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	BoastSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	BoastAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	int ret = clsuser->SendNewsToFriend(syn.gid, syn.type + boast_rank_up, syn.recv_heart_count);
	if (ret != ACK_OK)
	{
		SendFailAck(pchannelserver, ack, ret);
		return;
	}

	ack.heart_count = clsuser->AddHeartCount(syn.heart_count_max, syn.send_heart_count);
	ack.result = ACK_OK;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnUseBuffSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	UseBuffSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	UseBuffAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	time_t curtime = time(NULL);
	Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_info_friends_buff(", syn.seq, ",", syn.gid, ",", curtime + ONE_DAY, ")");
	if (0 != res.GetSQLError())
	{
		SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
		return;
	}

	int ret = clsuser->SetBuffTime(syn.gid, curtime+(ONE_MIN * syn.buff_time), static_cast<int>(use_friend_buff));
	if (ret != ACK_OK)
	{
		SendFailAck(pchannelserver, ack, ret);
		return;
	}

	ret = clsuser->SendNewsToFriend(syn.gid, static_cast<int>(use_friend_buff), syn.recv_heart_count);
	if (ret != ACK_OK)
	{
		SendFailAck(pchannelserver, ack, ret);
		return;
	}

	if (clsuser->GetBuffTime() > curtime)
		ack.buff_time = clsuser->GetBuffTime() - curtime;
	else
		ack.buff_time = 0;

	ack.heart_count = clsuser->AddHeartCount(syn.heart_count_max, syn.send_heart_count);

	pchannelserver->SendMsg(ack);
}

void
Msg::OnInviteFriendInGameSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	GameFriendSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	GameFriendAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	if (false == clsuser->GetIsAllow())
	{
		SendFailAck(pchannelserver, ack, ACK_MAX_FRIENDS);
		return;
	}

	auto & frtree = clsuser->GetFriendsTree();
	auto fritr = frtree.find(syn.gid);
	if (frtree.end() != fritr)
	{
		// 이미 요청중 처리
		if (fritr->second.friendType == 3)
		{
			ack.result = ACK_OF_THE_REQUESTS;
			pchannelserver->SendMsg(ack);
			return;
		}
	}

	auto & deleteFriendTree = clsuser->GetDeleteFriendsTree();
	auto delFriter = deleteFriendTree.find(syn.gid);
	// 삭제 친구 확인
	if (deleteFriendTree.end() != delFriter)
	{
		if (delFriter->second != 0 && delFriter->second + ONE_DAY > time(NULL))
		{
			ack.result = ACK_TIME_LEFT;
			pchannelserver->SendMsg(ack);
			return;
		}
		else
			deleteFriendTree.erase(syn.gid);
	}

	User::UserInfo clsUserInfo;
	if (Memcache->GetInfoSocialOther(clsuser, syn.gid, clsUserInfo) != ACK_OK)
	{
		SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
		return;
	}

	// 친구 요청 소식 보내기
	int ret = clsuser->SendNewsToFriend_Invite(clsUserInfo.shard_db_type, syn.gid, static_cast<int>(recv_request_friend), syn.recv_heart_count);
	if (ret != ACK_OK)
	{
		SendFailAck(pchannelserver, ack, ret);
		return;
	}

	ack.heart_count = clsuser->AddHeartCount(syn.heart_count_max, syn.send_heart_count);

	// 친구 추가
	User::FriendInfo frinfo;
	frinfo.friendType = 3; // 요청중으로 추가
	frtree[syn.gid] = frinfo;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnConfirmFriendSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	ConfirmFriendSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	ConfirmFriendAck ack;
	ack.seq = syn.seq;
	ack.gid = syn.gid;
	ack.news_seq = syn.news_seq;
	ack.is_accept = syn.is_accept;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	// 거절
	if (0 == syn.is_accept)
	{
		Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_data_news_status(", syn.news_seq, ",1)" );
		if (0 != res.GetSQLError())
		{
			LOG(ERR, "newsdata errno:", errno);
			ack.result = ACK_DB_ERROR;
		}

		pchannelserver->SendMsg(ack);
		return;
	}

	if (false == clsuser->GetIsAllow())
	{
		SendFailAck(pchannelserver, ack, ACK_MAX_FRIENDS);
		return;
	}

	// 수락
	if (1 == syn.is_accept)
	{
		int ret = clsuser->AddFriendAndInsertDB_InGame(syn.gid, syn.news_seq);
		if (ACK_OK != ret)
		{
			SendFailAck(pchannelserver, ack, ret);
			return;
		}
	}

	pchannelserver->SendMsg(ack);
}

void
Msg::OnRequestConnectSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	RequestConnectSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	RequestConnectAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	auto & frtree = clsuser->GetFriendsTree();

	auto fritr = frtree.find(syn.gid);
	if (frtree.end() == fritr)
	{
		LOG(DEV, "not found user");
		return;
	}

	time_t curtime = time(NULL);
	if (fritr->second.connectReqTime < curtime)
	{
		Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_info_friends_connectreqtime(", syn.seq, ",", syn.gid, ",", curtime + ONE_DAY, ")");
		if (0 != res.GetSQLError())
		{
			SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
			return;
		}

		fritr->second.connectReqTime = curtime + ONE_DAY;

		User::UserInfo userinfo;
		int ret = Memcache->GetInfoSocialOther(clsuser, syn.gid, userinfo);
		if (ACK_OK != ret)
		{
			SendFailAck(pchannelserver, ack, ret);
			return;
		}

		int noPlayDay = 0;
		if (curtime - userinfo.lastLoginTime != 0)
			noPlayDay = (curtime - userinfo.lastLoginTime) / ONE_DAY;

		uint32_t heartCount = 0;

		heartCount = noPlayDay * syn.sleeping_user_invite_heart_point_reward;
		if (0 == heartCount)
			heartCount = 1;

		if (syn.sleeping_user_invite_heart_point_reward_max < heartCount)
			heartCount = syn.sleeping_user_invite_heart_point_reward_max;

		ack.heart_count = clsuser->AddHeartCount(syn.heart_count_max, heartCount);

		heartCount = noPlayDay * syn.sleeping_user_be_invited_heart_point_reward;
		if (0 == heartCount)
			heartCount = 1;

		if (syn.sleeping_user_be_invited_heart_point_reward_max < heartCount)
			heartCount = syn.sleeping_user_be_invited_heart_point_reward_max;

		uint32_t newsType = send_msg_come_on_sleeping_user_0 + noPlayDay;
		if (send_msg_come_on_sleeping_user_max < newsType)
			newsType = send_msg_come_on_sleeping_user_max;

		clsuser->SendNewsToFriend(syn.gid, newsType, heartCount);
	}
	else
		ack.result = ACK_UNKNOWN_ERROR;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnConfirmNewsSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	ConfirmNewsSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	ConfirmNewsAck ack;
	ack.seq = syn.seq;
	ack.news_seq = syn.news_seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	if (2 == syn.type)
	{
	// 모두확인
		// 전체 heart count 모두 반영
		// 소식 업데이트
		Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_data_news_status_all(", syn.seq, ", 2)" );

		if (0 != res.GetSQLError())
		{
			LOG(ERR, "newsdata errno:", errno);
			ack.result = ACK_DB_ERROR;
		}

		if (res.end() == res.begin())
		{
			LOG(DEV, "sp_update_allnews result is null" );
			SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
			return;
		}

		for(Database::ResultSet::iterator itr = res.begin(); itr != res.end(); itr++)
		{
			clsuser->AddHeartCount(syn.heart_count_max, itr->getInt("heart_count"));
		}
	}
	else if (0 == syn.type)
	{
		// 한건 확인
		// heart count 조회
		// 소식 업데이트
		Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_data_news_status(", syn.news_seq, ", 2)" );

		if (0 != res.GetSQLError())
		{
			LOG(ERR, "newsdata errno:", errno);
			ack.result = ACK_DB_ERROR;
		}

		if (res.end() == res.begin())
		{
			LOG(DEV, "sp_update_allnews result is null" );
			SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
			return;
		}

		for(Database::ResultSet::iterator itr = res.begin(); itr != res.end(); itr++)
		{
			clsuser->AddHeartCount(syn.heart_count_max, itr->getInt("heart_count"));
		}
	}

	ack.heart_count = clsuser->GetHeartCount();
	ack.result = ACK_OK;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnDeleteFriendSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	DeleteFriendSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	DeleteFriendAck ack;
	ack.seq = syn.seq;
	ack.gid = syn.gid;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	// 친구 삭제
	int res = clsuser->DeleteFriend(clsuser->GetUserInfo().shard_db_type, syn.seq, syn.gid);
	if (ACK_OK != res)
	{
		SendFailAck(pchannelserver, ack, res);
		return;
	}

	pchannelserver->SendMsg(ack);
}

void
Msg::OnFriendTypeModifySyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	FriendTypeModifySyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	LOG(DEV, "gid : ", syn.gid, "type : ", syn.type);

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		return;
	}

	auto & frtree = clsuser->GetFriendsTree();

	switch (syn.type)
	{
	// 상대방 친구가 나를 수락한 경우
	case 2:	// 친구 요청중 -> 친구 관계로 변경
	{
		User::UserInfo userinfo;
		Memcache->GetInfoSocialOther(clsuser, syn.gid, userinfo);

		User::FriendInfo frinfo;
		frinfo.friendType = 2;
		frinfo.socialID = syn.socialid;
		frinfo.shard_db_type = userinfo.shard_db_type;
		frtree[syn.gid] = frinfo;
	}
	break;

	case 4: // 상대방 친구가 나를 삭제 한 경우
		frtree.erase(syn.gid);
		break;

		// 상대방 친구가 나를 거절한 경우
	case 5:	// 요청 거절로 상대방 트리에서 제거
		frtree.erase(syn.gid);
		break;
	}
}

void
Msg::OnFlushUserInfo(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	FlushFRUserInfoSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);

	FlushFRUserInfoAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	ack.result = clsuser->FlushUserInfo();

	pchannelserver->SendMsg(ack);
}

void
Msg::OnRemoveUser(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	RemoveFRUserSyn syn;
	pPacket->Read(syn);
	RemoveFRUserAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		ack.result = ACK_EXIST_USER;
		pchannelserver->SendMsg(ack);
		LOG(DEV, "not found user userkey : ", syn.seq );
		return;
	}

	LOG(DEV, "OnRemoveUser found user seq : ", syn.seq );

	clsuser->SetTimer();

	ack.result = ACK_OK;
	pchannelserver->SendMsg(ack);
}

void
Msg::OnCheckEnableAllowSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	AllowFriendSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	AllowFriendAck ack;
	ack.seq = syn.userseq;
	ack.userseq = syn.seq;
	ack.msgid = syn.msgid;
	ack.dummy = syn.dummy;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser) // 유저 로그 아웃 상태
	{
		int shard_db_type = 0;
		LOG(DEV, "not found user userkey : ", syn.seq );
		{
			Database::ResultSet res = Database::Execute(2, "call sp_select_info_user_shard_db_type(", syn.seq, ")");
			if (0 != res.GetSQLError())
			{
				LOG(DEV, "sp_select_info_user_seq errno : ", errno );
				return;
			}

			for(auto itr = res.begin(); itr != res.end(); itr++)
			{
				shard_db_type = itr->getInt("shard_db_type");
			}
		}

		Database::ResultSet res = Database::Execute(shard_db_type, "call sp_select_info_friends_count(", syn.seq, ")" );
		if (0 != res.GetSQLError())
		{
			LOG(ERR, "newsdata errno:", errno);
			ack.is_allow = 0;
			SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
			return;
		}
		if (res.end() == res.begin())
		{
			LOG(DEV, "sp_allow_friend result is null" );
			ack.is_allow = 0;
			SendFailAck(pchannelserver, ack, ACK_NO_DATA);
			return;
		}

		int count = 0;
		for(auto itr = res.begin(); itr != res.end(); itr++)
		{
			count = itr->getInt("cnt");
		}

		ack.is_allow = (GAME_FRIEND_MAX - count) > 0 ? 1: 0;
		pchannelserver->SendMsg(ack);
		return;
	}

//	ack.is_allow = (GAME_FRIEND_MAX - clsuser->GetFriendsTree().size()) > 0 ? 1: 0;
	ack.is_allow = clsuser->GetIsAllow();
	pchannelserver->SendMsg(ack);
}

void
Msg::OnInviteCount(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	InviteCountSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	InviteCountAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	ack.invite_count = clsuser->GetInviteCount();
	pchannelserver->SendMsg(ack);
}

void
Msg::OnGachyaBoxSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	GachyaBoxSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	GachyaBoxAck ack;
	ack.seq = syn.seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	ack.heart_count = clsuser->SubtractHeartCount(syn.box_open_point);
	ack.result = ACK_OK;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnLastWeekRankInfoSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	LastWeekRankInfoSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	LastWeekRankInfoAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	// 내 등수 구하기
	int16_t eRes = clsuser->GetMyRanking();

	ack.my_ranking				= clsuser->GetMyRank();
	ack.last_week_friend_count	= clsuser->GetFriendRankCount();
	ack.result = eRes;

	pchannelserver->SendMsg(ack);
}

void
Msg::OnGetHeartCountSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	GetHeartCountSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	GetHeartCountAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	ack.heart_count = clsuser->GetHeartCount();
	pchannelserver->SendMsg(ack);
}

void
Msg::OnAddHeartCountSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	AddHeartCountSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	AddHeartCountAck ack;
	ack.seq = syn.seq;
	ack.msgid = syn.msgid;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	ack.heart_count = clsuser->AddHeartCount(syn.heart_count_max, syn.get_heart_count);
	pchannelserver->SendMsg(ack);
}

void
Msg::OnFriendKillTimerSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket)
{
	FriendKillTimerSyn syn;
	pPacket->Read(syn);

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		return;
	}

	clsuser->KillTimer();
}

void
Msg::OnUnregister(Dispatcher::Session* pSession, ::Network::Packet * pPacket )
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;
	UnregisterSyn syn;
	pPacket->Read(syn);
	LOG(DEV, "MSG_ID : ", syn.MSG_ID, "SEQ : ", syn.seq);
	UnregisterAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	clsuser->GetUserInfo().unregister_time = time(NULL);

	Memcache->SetMyInfo(clsuser);
}

void
Msg::OnSendStaminaSyn(Dispatcher::Session* pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;

	SendStaminaSyn syn;
	pPacket->Read(syn);

	LOG(DEV, "MSG_ID : ", syn.MSG_ID, " SEQ : ", syn.seq);

	SendStaminaAck ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	User::FRIENDSTREE & friendstree = clsuser->GetFriendsTree();

	User::FRIENDSTREE::iterator fritr = friendstree.find(syn.gid);
	if (friendstree.end() == fritr)
	{
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

	time_t curtime = time(NULL);

	if (fritr->second.heartTime > curtime)
	{
		SendFailAck(pchannelserver, ack, ACK_UNKNOWN_ERROR);
		return;
	}

	fritr->second.heartTime = curtime + ONE_DAY;

	Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_info_friends_heart_date(", syn.seq, ",", syn.gid, ",", curtime + ONE_DAY, ")");
	if (0 != res.GetSQLError())
	{
		SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
		return;
	}

	// 친구에게 우정포인트 1 발송
	int ret = clsuser->SendNewsToFriend(syn.gid, static_cast<int>(recv_friendship_point), syn.send_heart_count);
	if (ret != ACK_OK)
	{
		SendFailAck(pchannelserver, ack, ret);
		return;
	}

	// 친구에게 스태미너 3 발송
	ret = clsuser->SendNewsToFriend(syn.gid, static_cast<int>(recv_stamina_point), syn.send_stamina_count);
	if (ret != ACK_OK)
	{
		SendFailAck(pchannelserver, ack, ret);
		return;
	}

	pchannelserver->SendMsg(ack);
}

void
Msg::OnConfirmNewsV2Syn(Dispatcher::Session* pSession, ::Network::Packet * pPacket)
{
	ChannelServer * pchannelserver = (ChannelServer *)pSession;

	ConfirmNewsV2Syn syn;
	pPacket->Read(syn);

	LOG(DEV, "MSG_ID : ", syn.MSG_ID, " SEQ : ", syn.seq);

	ConfirmNewsV2Ack ack;
	ack.seq = syn.seq;
	ack.result = ACK_OK;
	ack.news_seq = syn.news_seq;

	auto clsuser = Static::Instance().GetUser(syn.seq);
	if (NULL == clsuser)
	{
		LOG(DEV, "not found user userkey : ", syn.seq );
		SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
		return;
	}

    if (0 == syn.confirm_type)
    {
		// 한건 확인
		Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_select_data_news_info(", syn.news_seq, ")" );

		if (0 != res.GetSQLError())
		{
			LOG(ERR, "sp_select_data_news_info errno:", errno);
			SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
			return;
		}

		if (res.end() == res.begin())
		{
			LOG(DEV, "sp_select_data_news_info result is null" );
			SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
			return;
		}

		int news_type = 0;
		int reward_count = 0;

		for(Database::ResultSet::iterator itr = res.begin(); itr != res.end(); itr++)
		{
			news_type = itr->getInt("type");
			reward_count = itr->getInt("heart_cnt");
		}

		if (news_type == static_cast<int>(recv_stamina_point))
		{
			// 구매 및 친구 소식으로 충전할 수 있는 스태미너 MAX값을 초과하는 경우
			if (syn.max_stamina < (syn.cur_stamina + reward_count) )
			{
				SendFailAck(pchannelserver, ack, ACK_STAMINA_MAX_OVERFLOW);
				return;
			}

			// 하루에 받을 수 있는 스태미너 개수를 초과한 경우
			if (0 >= syn.remain_recv_stamina)
			{
				ack.heart_count = clsuser->GetHeartCount();
				SendFailAck(pchannelserver, ack, ACK_NOT_RECV_STAMINA);
				return;
			}

			// 스태미너 소식 업데이트
			Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_data_news_info(", syn.news_seq, ", 2)" );

			if (0 != res.GetSQLError())
			{
				LOG(ERR, "sp_update_data_news_info stamina errno:", errno);
				SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
				return;
			}

			ack.charge_stamina_count = reward_count;
		}
		else
		{
			// 우정 포인트 소식 업데이트
			Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_data_news_info(", syn.news_seq, ", 2)" );

			if (0 != res.GetSQLError())
			{
				LOG(ERR, "sp_update_data_news_info heart_point errno:", errno);
				SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
				return;
			}

			clsuser->AddHeartCount(syn.max_heart, reward_count);
		}
    }
    else if (2 == syn.confirm_type)
    {
    	// 모두 확인
		Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_select_data_news_info_all(", syn.seq, ")" );

		if (0 != res.GetSQLError())
		{
			LOG(ERR, "sp_select_data_news_info_all errno:", errno);
			SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
			return;
		}

		if (res.end() == res.begin())
		{
			LOG(DEV, "sp_select_data_news_info_all result is null" );
			SendFailAck(pchannelserver, ack, ACK_EXIST_USER);
			return;
		}

		int heart_count = 0;
		int stamina_count = 0;

		for(Database::ResultSet::iterator itr = res.begin(); itr != res.end(); itr++)
		{
			heart_count = itr->getInt("heart_count");
			stamina_count = itr->getInt("stamina_count");
		}

		// 받을 수 있는 우정 포인트가 있는 경우 반영한다
		if (0 < heart_count)
		{
			// 우정 포인트 소식 업데이트
			Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_data_news_info_all(", syn.seq, ", 0, 0, 2)" );

			if (0 != res.GetSQLError())
			{
				LOG(ERR, "sp_update_data_news_info_all heart_point errno:", errno);
				SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
				return;
			}

			clsuser->AddHeartCount(syn.max_heart, heart_count);
		}

		// 받을 스태미너 소식이 없는 경우
		if (0 >= stamina_count)
		{
			ack.result = ACK_OK;
			ack.charge_stamina_count = 0;
		    ack.heart_count = clsuser->GetHeartCount();
		    pchannelserver->SendMsg(ack);
		    return;
		}

		// 전체 스태미나 소식 갯수 (소식 한건당 스태미너는 3개)
		int total_stamina_news = stamina_count / 3;

		// 하루 수신 가능한 스태미너(MAX 24)기준으로 받을 수 있는 스태미너 소식 갯수
		int limit_daily = syn.remain_recv_stamina / 3;

		// 최대 스태미너 보유 수량(MAX 256) 기준으로 받을 수 있는 스태미너 소식 갯수
		int limit_max = (syn.max_stamina - syn.cur_stamina) / 3;

		// 최대 스태미너 보유 수량을 초과하여 받을 수 없다
		if (0 >= limit_max)
		{
			ack.result = ACK_STAMINA_MAX_OVERFLOW;
			ack.charge_stamina_count = 0;
		    ack.heart_count = clsuser->GetHeartCount();
		    pchannelserver->SendMsg(ack);
		    return;
		}

		// 최종적으로 받을 스태미너 소식 갯수
		int recv_stamina_news = (limit_daily > limit_max) ? limit_max : limit_daily;
		recv_stamina_news = (recv_stamina_news > total_stamina_news) ? total_stamina_news : recv_stamina_news;

		if (0 < recv_stamina_news)
		{
			// 스테미너 소식 업데이트
			Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_data_news_info_all("
					, syn.seq, ", 1,", recv_stamina_news, ", 2)");

			if (0 != res.GetSQLError())
			{
				LOG(ERR, "sp_update_data_news_info_all stamina errno:", errno);
				SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
				return;
			}
		}

		ack.charge_stamina_count = recv_stamina_news * 3;

		// 하루에 받을 수 있는 스태미너를 초과한 경우 (하루 MAX 24)
		if (0 >= (syn.remain_recv_stamina - ack.charge_stamina_count) )
		{
			ack.result = ACK_NOT_RECV_STAMINA;
		}

		// 최대 보유 수량을 초과하는 경우 (최대 MAX 256)
		int remain_stamina_count = (total_stamina_news - recv_stamina_news) * 3;

		if (syn.max_stamina <= (syn.cur_stamina + ack.charge_stamina_count + remain_stamina_count) )
		{
			ack.result = ACK_STAMINA_MAX_OVERFLOW;
		}
    }

    ack.heart_count = clsuser->GetHeartCount();

    pchannelserver->SendMsg(ack);


#if 0
		// 소식으로 받을 수 있는 스태미너는 최대 256
		if (syn.max_stamina < (syn.cur_stamina + syn.remain_recv_stamina) )
		{
			recv_stamina_news = (syn.max_stamina - syn.cur_stamina) / 3;
		}

		if (total_stamina_news >= recv_stamina_news)
		{
			if (0 < recv_stamina_news)
			{
				// 스테미너 소식 업데이트
				Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_data_news_info_all("
						, syn.seq, ", 1,", recv_stamina_news, ", 2)");

				if (0 != res.GetSQLError())
				{
					LOG(ERR, "sp_update_data_news_info_all stamina errno:", errno);
					SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
					return;
				}
			}

			ack.charge_stamina_count = recv_stamina_news * 3;

			// 하루에 받을 수 있는 스태미너를 초과한 경우 (하루 MAX 24)
			if (0 >= (syn.remain_recv_stamina - ack.charge_stamina_count) )
			{
				ack.result = ACK_NOT_RECV_STAMINA;
			}
		}
		else
		{
			if (0 < stamina_count && 0 < recv_stamina_news)
			{
				// 스테미너 소식 업데이트
				Database::ResultSet res = Database::Execute(clsuser->GetUserInfo().shard_db_type, "call sp_update_data_news_info_all("
						, syn.seq, ", 1, 0, 2)");

				if (0 != res.GetSQLError())
				{
					LOG(ERR, "sp_update_data_news_info_all stamina errno:", errno);
					SendFailAck(pchannelserver, ack, ACK_DB_ERROR);
					return;
				}
			}

			ack.charge_stamina_count = stamina_count;
		}
    }

    ack.heart_count = clsuser->GetHeartCount();

    pchannelserver->SendMsg(ack);
#endif
}

} /* namespace FriendsServer */




